//------------------------------------------------------------------------------
// <copyright file="RpcRequest.cpp" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#include "stdafx.h"

#include <rpc.h> // This is the Windows RPC header.

#include "RpcRequest.h"
#include <RpcArchive.h>
#include <RpcArchiveImpl.h>
#include <RpcArchiveImplFactory.h>

using namespace Microsoft::Internal::GamesTest::Rpc::Server;

const wchar_t MethodNameKey[] = L"methodName";
const wchar_t ParametersKey[] = L"parameters";
const wchar_t RequestIdKey[] = L"requestId";

GAMESTEST_ANNOTATE_HRESULT_METHOD HRESULT RpcRequest::Parse(const std::wstring& request, RpcRequest* result)
{
	HRESULT hr = E_FAIL;	

	VERIFY_PARAM_NOT_NULL(result);

	try
	{
		JsonNode jsonRequest;
		jsonRequest.Parse(request);

		result->m_methodName = jsonRequest.GetStringValue(MethodNameKey);
		result->m_parameters = RpcArchiveImplFactory::Deserialize(jsonRequest.GetValue(ParametersKey));
		result->m_requestId = (RequestIdType)jsonRequest.GetNumericValue(RequestIdKey);
	}
	catch (std::out_of_range)
	{
		hr = E_INVALID_PROTOCOL_FORMAT;
		goto end;
	}
	catch (std::invalid_argument)
	{
		if (request.empty())
		{
			hr = E_INVALIDARG;
		}
		else
		{
			hr = E_INVALID_PROTOCOL_FORMAT;
		}

		goto end;
	}

end:
	return hr;
}

GAMESTEST_ANNOTATE_HRESULT_METHOD HRESULT RpcRequest::PreParse(const std::wstring& requestObject, std::wstring& methodName)
{
	// Get string characters
	const wchar_t* data = requestObject.c_str();

	// Find the methodName key
	const wchar_t* methodNameStart = wcsstr(data, L"methodName");

	if (methodNameStart == NULL)
	{
		return E_INVALID_PROTOCOL_FORMAT;
	}

	// Find the key-value separator (':')
	methodNameStart = wcschr(methodNameStart, L':');

	if (methodNameStart == NULL)
	{
		return E_INVALID_PROTOCOL_FORMAT;
	}

	// Find the start of value
	methodNameStart = wcschr(methodNameStart, L'\"');

	if (methodNameStart == NULL)
	{
		return E_INVALID_PROTOCOL_FORMAT;
	}

	// Find the end of value
	const wchar_t* methodNameEnd = wcschr(methodNameStart + 1, L'\"');

	if (methodNameEnd == NULL)
	{
		return E_INVALID_PROTOCOL_FORMAT;
	}

	// Extract methodName value
	methodName = std::wstring(methodNameStart + 1, (size_t)(methodNameEnd - methodNameStart - 1));

	return S_OK;
}

GAMESTEST_ANNOTATE_HRESULT_METHOD HRESULT RpcRequest::Serialize(std::wstring& result)
{
	JsonNode jsonObject;

	jsonObject.SetValue(MethodNameKey, m_methodName);
	jsonObject.SetValue(RequestIdKey, (double)m_requestId);
	jsonObject.SetValue(ParametersKey, m_parameters->GetJson());

	result = jsonObject.Serialize();

	return S_OK;
}